(function (global, factory) {
    "use strict";
    if (typeof module === "object" && typeof module.exports === "object") {
        module.exports = factory(global, true);
    } else {
        factory(global);
    }
})(
    typeof window !== "undefined" ? window : this,
    function factory(window, noGlobal) {
        // 笼统检测是否为对象
        const isObject = function isObject(obj) {
            return obj !== null && /^(object|function)$/.test(typeof obj);
        };

        // 检测是否是window对象
        const isWindow = function isWindow(obj) {
            return obj != null && obj === obj.window;
        };

        // 检测是否为数组或者伪数组
        const isArrayLike = function isArrayLike(obj) {
            if (Array.isArray(obj)) return true;
            // 检测是否为伪数组
            let length = !!obj && 'length' in obj && obj.length;
            if (typeof obj === "function" || isWindow(obj)) return false;
            return length === 0 ||
                typeof length === "number" && length > 0 && (length - 1) in obj;
        };

        // 迭代数组、伪数组、对象「支持中途结束循环」
        const each = function each(obj, callback) {
            if (typeof callback !== "function") callback = () => { };
            // 让其支持“纯数字”控制循环
            if (typeof obj === "number" && !isNaN(obj) && obj > 0) {
                obj = new Array(obj).fill(null);
            }
            // 让其支持字符串
            if (typeof obj === "string") obj = Object(obj);
            if (!isObject(obj)) return obj;
            // 迭代数组/伪数组
            if (isArrayLike(obj)) {
                for (let i = 0; i < obj.length; i++) {
                    let item = obj[i];
                    let res = callback.call(obj, item, i);
                    if (res === false) break;
                }
                return obj;
            }
            // 迭代对象
            let keys = Reflect.ownKeys(obj);
            for (let i = 0; i < keys.length; i++) {
                let key = keys[i],
                    value = obj[key];
                let res = callback.call(obj, value, key);
                if (res === false) break;
            }
            return obj;
        };

        // 转移“_”的使用权
        let origin = null;
        const noConflict = function noConflict() {
            if (window._ === utils) {
                window._ = origin;
            }
            return utils;
        };

        /* 暴露API */
        const utils = {
            isObject,
            isArrayLike,
            isWindow,
            noConflict,
            each
        };
        if (typeof noGlobal === "undefined") {
            origin = window._;
            window.utils = window._ = utils;
        }
        return utils;
    }
);